package cn.ex.ymcc.service.impl;

import ch.qos.logback.classic.Logger;
import cn.ex.ymcc.domain.Course;
import cn.ex.ymcc.domain.CourseMarket;
import cn.ex.ymcc.domain.KillActivity;
import cn.ex.ymcc.domain.KillCourse;
import cn.ex.ymcc.dto.KillParamDto;
import cn.ex.ymcc.dto.KillPreOrderParamsDto;
import cn.ex.ymcc.mapper.KillCourseMapper;
import cn.ex.ymcc.service.IKillActivityService;
import cn.ex.ymcc.service.IKillCourseService;
import cn.ex.ymcc.util.AssertUtil;
import cn.ex.ymcc.util.CodeGenerateUtils;
import cn.ex.ymcc.vo.CourseItemVo;
import cn.ex.ymcc.vo.CourserOrderVo;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * <p>
 *  秒杀业务的实现
 * </p>
 */
@Service
@Slf4j
public class KillCourseServiceImpl extends ServiceImpl<KillCourseMapper, KillCourse> implements IKillCourseService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private IKillActivityService killActivityService;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 保存秒杀课程
     * @param killCourse
     */
    @Override
    public void save(KillCourse killCourse) {
        //查询秒杀活动是否存在
        KillCourse killCourseTmp = selectByIdAndCourseID(killCourse.getActivityId(), killCourse.getCourseId());
        AssertUtil.isNull(killCourseTmp,"秒杀课程已经存在！");
        //添加活动
        KillActivity killActivity = killActivityService.selectById(killCourse.getActivityId());
        killCourse.setStartTime(killActivity.getBeginTime());
        killCourse.setEndTime(killActivity.getEndTime());
        killCourse.setTimeStr(killActivity.getTimeStr());
        killCourse.setCreateTime(new Date());
        //做活动新增
        insert(killCourse);
    }

    /**
     * 查询所有的秒杀课程
     * @return
     */
    @Override
    public List<KillCourse> onlineAll() {
        List<KillCourse> allKillCourse = new ArrayList<>();
        //获取当前秒杀活动下的所有key
        Set<Object> keys = redisTemplate.keys("activity:*");
        keys.forEach(bigKey->{
            List values = redisTemplate.opsForHash().values(bigKey);
            allKillCourse.addAll(values);
        });
        return allKillCourse;
    }

    @Override
    public KillCourse onlineOne(Long activityId, Long killId) {
        AssertUtil.isNotNull(activityId,"请求非法");
        AssertUtil.isNotNull(killId,"请求非法");
        Object killCourse = redisTemplate.opsForHash().get("activity:" + activityId, killId.toString());

        return (KillCourse) killCourse;
    }
    /**
     * 执行秒杀
     * @return
     */
    @Override
    public String kill(KillParamDto dto) {
        Long activityId = dto.getActivityId();
        Long killCourseId = dto.getKillCourseId();
        //查询秒杀课程
        KillCourse killCourse = onlineOne(activityId, killCourseId);
        //判断是否在秒杀的时间范围内
        AssertUtil.isTrue(killCourse.isKilling(),"报警了");
        //登陆成功的才能秒杀
        Long loginId = 1L;

        //设置redis存储的key
        String repeatKey = activityId +":"+killCourseId +":"+loginId;
        Object repeatOrder = redisTemplate.opsForValue().get(repeatKey);
        //不能重复秒杀
        AssertUtil.isNull(repeatOrder,"请勿重复秒杀！！");

        //使用信号量扣减库存
        String key = activityId +":"+killCourseId;
        //获取唯一的信号量对象
        RSemaphore semaphore = redissonClient.getSemaphore(key);
        //秒杀商品数量
        Integer killCount = 1;
        //获取单线程下的 许可
        boolean tryAcquire = semaphore.tryAcquire(killCount);
        //扣减不成功
        AssertUtil.isTrue(tryAcquire,"练练手速在来");

        String orderNo = CodeGenerateUtils.generateOrderSn(loginId);
        //扣减成功生成预创单
        KillPreOrderParamsDto killPreOrderParamsDto = new KillPreOrderParamsDto(
                orderNo,
                killCount,
                killCourse.getKillPrice(),
                loginId,
                killCourse.getCourseId(),//课程ID
                killCourse.getCourseName(),
                killCourse.getCoursePic()
        );
        //保存 订单号 和 预创单 redis
        redisTemplate.opsForValue().set(orderNo,killPreOrderParamsDto);
        //存储秒杀成功信息，防止重复秒杀
        redisTemplate.opsForValue().set(repeatKey,orderNo);
        return orderNo;
    }

    /**
     *返回秒杀订单结算页
     * @param orderNo
     * @return
     */
    @Override
    public CourserOrderVo oneByOrder(String orderNo) {
        //获取预创订单
        KillPreOrderParamsDto preOrder = (KillPreOrderParamsDto) redisTemplate.opsForValue().get(orderNo);
        //根据预创订单封装我们想要的Vo结构
        AssertUtil.isNotNull(preOrder,"请求非法！");
        //查询课程 + 销售表
        List<CourseItemVo> courseInfos = new ArrayList<>();
        Course course = new Course();
        course.setId(preOrder.getCourseId());
        course.setName(preOrder.getCourseName());
        course.setPic(preOrder.getCoursePic());

        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setPrice(preOrder.getKillAmount());

        CourseItemVo courseItemVo = new CourseItemVo(course, courseMarket);
        courseInfos.add(courseItemVo);
        //返回总金额和课程明细
        return new CourserOrderVo(courseInfos,preOrder.getKillAmount());
    }

    private KillCourse selectByIdAndCourseID(Long activityId, Long courseId) {
        Wrapper<KillCourse> query = new EntityWrapper<>();
        query.eq("course_id",courseId);
        query.eq("activity_id",activityId);
        return selectOne(query);
    }


}
